package empe;

/**
 * Elemento que estende o elemento basico (Cap_elemento) de modo a adicionar-lhe
 * a referencia do individuo e uma lista privada a qual e' inteiramente
 * gerida nesta classe, ie, cada evento gere os seus proprios apontadores da
 * lista pessoal do individuo.
 */
public abstract class Evento extends Cap_elemento {

	protected Evento prox_evento_individuo; 
	protected Evento ant_evento_individuo;
	protected Individuo individuo;



	/**
	 * Remove eventos da lista pessoal do individuo.
	 * (actualização de referências apenas)
	 */
	protected void remove_lista_evento_individuo() {

		if(this.ant_evento_individuo == null) { /*significa que e' o primeiro*/
			this.individuo.eventos = this.prox_evento_individuo;
			if(this.prox_evento_individuo != null) /*salvaguarda o caso em que e' o primeiro e unico*/
				this.prox_evento_individuo.ant_evento_individuo = null; /*elimina a referência pra ele próprio*/
		}
		else {
			if(this.prox_evento_individuo != null)  /*não e' o ultimo*/
				this.prox_evento_individuo.ant_evento_individuo = this.ant_evento_individuo;

			this.ant_evento_individuo.prox_evento_individuo = this.prox_evento_individuo;
			this.ant_evento_individuo = this.prox_evento_individuo = null; /*so porque sim*/
		}

	}


	/**
	 * Insere sempre no inicio da lista pessoal do individuo, desta forma e' garantido 
	 * (pela ordem de insercao) que a morte sera sempre o primeiro evento da lista pessoal
	 * (actualização de referencias apenas) 
	 * O retorno desta funcao e' usado para saber se o evento era valido, ie,
	 * ocorre antes do evento morte.
	 * @return booleano que indica se o evento foi inserido ou nao.
	 */
	protected boolean insere_lista_evento_individuo() {

		Evento aux;
		boolean inserido = false;

		if(this.individuo.eventos == null) {

			this.individuo.eventos = this;
			this.prox_evento_individuo = null;
			this.ant_evento_individuo = null;
			inserido = true;
		}
		else { 
			aux = (Evento) this.individuo.eventos;

			if(this.tempo < aux.tempo) { /*se tem um tempo menor do que o da morte*/

				while(aux.prox_evento_individuo != null) {
					aux = aux.prox_evento_individuo;
				}/*aux tem o ultimo elemento, não null*/

				/* apenas compara mutações com reproduções, dado que se for uma morte
				 * não chega a este ponto de execução
				 * Garante que não temos 2 eventos no mesmo instante
				 */
				if(aux.tempo == this.tempo) this.tempo = this.tempo + 1;

				aux.prox_evento_individuo = this;
				this.prox_evento_individuo = null;
				this.ant_evento_individuo = aux;
				inserido = true;

			}
		}

		return inserido;
	}


	/**
	 * Realiza as operacoes necessarias ao tratamento do evento
	 */
	protected abstract Evento simular();


	/**
	 * Gera uma observacao da variavel aleatoria
	 */
	protected abstract int calcular_tempo();

}
